"""
观察者模式示例：当事件发生时，自动通知所有观察者
简单理解：就像朋友圈，当你发了一条动态，所有关注你的人都会收到通知
"""

from typing import List, Callable


class PostEvent:
    """帖子事件类：封装事件信息"""
    
    def __init__(self, event_type: str, post_id: int, user_id: int = None):
        # 事件类型：'like'(点赞), 'view'(浏览), 'comment'(评论)
        self.event_type = event_type
        
        # 帖子ID
        self.post_id = post_id
        
        # 用户ID（可选）
        self.user_id = user_id


class PostObserver:
    """帖子观察者：监听帖子事件"""
    
    def __init__(self):
        # 存储所有观察者函数的列表
        # 使用Callable类型提示表示可调用对象
        self._observers: List[Callable] = []
    
    def attach(self, observer: Callable):
        """
        添加观察者（订阅事件）
        
        业务场景:
        当我们需要为某种事件增加新的处理逻辑时，
        可以通过attach方法动态添加观察者，而不需要修改现有代码
        
        实现原理:
        将观察者函数添加到观察者列表中
        """
        # 避免重复添加同一个观察者
        if observer not in self._observers:
            self._observers.append(observer)
    
    def detach(self, observer: Callable):
        """
        移除观察者（取消订阅）
        
        业务场景:
        当我们不再需要某个处理逻辑时，可以通过detach方法移除观察者
        
        实现原理:
        从观察者列表中移除指定的观察者函数
        """
        # 只有当观察者存在于列表中时才移除
        if observer in self._observers:
            self._observers.remove(observer)
    
    def notify(self, event: PostEvent):
        """
        通知所有观察者（触发事件）
        
        观察者模式应用场景:
        在我们的项目中，当帖子被浏览、点赞或评论时，
        会触发观察者模式，通知所有注册的观察者进行相应处理
        
        核心角色:
        1. 主题/被观察者(PostObserver) - 管理观察者列表并通知它们
        2. 观察者(具体函数) - 实现对事件的处理逻辑
        3. 事件(PostEvent) - 包含事件相关信息的数据对象
        
        实现原理:
        遍历观察者列表，逐个调用观察者的处理函数
        
        实现流程:
        1. 创建事件对象，包含事件相关信息
        2. 调用notify方法，传入事件对象
        3. notify方法遍历所有观察者
        4. 每个观察者接收到事件对象并进行处理
        
        可能遇到的问题及优化:
        1. 问题：某个观察者执行出错会影响其他观察者
           优化：使用try-except捕获异常，确保所有观察者都能执行
        2. 问题：观察者执行顺序不确定
           优化：可以使用优先级队列管理观察者
        3. 问题：观察者之间可能存在依赖关系
           优化：可以实现观察者间的协调机制
        
        为什么选择观察者模式而不是直接调用函数:
        1. 解耦：事件发布者和订阅者互不依赖
        2. 动态扩展：可以随时添加或移除观察者
        3. 一对多：一个事件可以通知多个观察者
        4. 符合开闭原则：增加新观察者不需要修改现有代码
        """
        # 遍历所有观察者并通知它们
        for observer in self._observers:
            try:
                # 调用观察者的处理函数
                observer(event)
            except Exception as e:
                # 捕获异常，避免一个观察者出错影响其他观察者
                print(f"观察者执行出错: {e}")


# 全局观察者实例（单例模式）
# 在整个应用中使用同一个观察者实例
post_observer = PostObserver()


# ============ 定义具体的观察者函数 ============

def update_statistics(event: PostEvent):
    """
    观察者1：更新统计数据
    
    业务场景:
    当帖子被浏览、点赞或评论时，需要更新相应的统计数据
    
    实现原理:
    根据事件类型更新帖子的浏览数、点赞数或评论数
    """
    print(f"📊 [统计] 帖子 {event.post_id} 发生了 {event.event_type} 事件，正在更新统计数据...")


def send_notification(event: PostEvent):
    """
    观察者2：发送通知
    
    业务场景:
    当帖子被浏览、点赞或评论时，需要通知帖子作者
    
    实现原理:
    根据事件类型向帖子作者发送相应的通知消息
    """
    print(f"🔔 [通知] 帖子 {event.post_id} 有新的 {event.event_type} 操作，正在通知作者...")


def log_event(event: PostEvent):
    """
    观察者3：记录日志
    
    业务场景:
    当帖子发生重要事件时，需要记录日志用于后续分析
    
    实现原理:
    将事件信息写入日志文件或数据库
    """
    print(f"📝 [日志] 记录事件: {event.event_type} - 帖子ID: {event.post_id}")


# ============ 注册观察者 ============
# 当应用启动时，自动注册所有观察者
# 这样当事件发生时，所有观察者都会被通知到
post_observer.attach(update_statistics)
post_observer.attach(send_notification)
post_observer.attach(log_event)